package game.server;

import game.Game;
import game.log.Logger;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.Date;

import shared.io.game.Maze2;
import shared.io.game.Player;
import shared.io.messages.ServerMessage;
import shared.io.startup.ClientStartup;
import shared.io.startup.NewGame;
import shared.io.startup.PlayerStartup;

/**
 * Client Session.
 */
public class ClientSession extends Thread {
   
   private ObjectInputStream in;
   private ObjectOutputStream out;
   private Object inObject;
   private Server server;
   private Player player;
   private Game game;
   
   public ClientSession(Socket socket, Server server, Game game) throws IOException {
      Logger.write("Client connected to the server.");
      this.server = server;
      this.game = game;
      out = new ObjectOutputStream(socket.getOutputStream());
      in = new ObjectInputStream(socket.getInputStream());
   }
   
   /**
    * Sends an object to the client.
    */
   public void sendObject(Object object) {
      synchronized (game) {
         try {
            out.writeObject(object);
            out.reset();
         } catch (IOException e) {
            Logger.write("Failed to send object (" + object + ").");
         }
      }
   }

   @Override
   public void run() {
      try {
         while ((inObject = in.readObject()) != null) {
            server.manageObject(inObject, this);
         }
      } catch (ClassNotFoundException e) {
         close();
      } catch (IOException e) {
         close();
      } finally {
         close();
      }
   }
   
   /**
    * Closes the clientSession
    */
   public void close() {
      Date date = new Date();
      Logger.write("Client disconnected from the server.");
      try {
         in.close();
         out.close();
      } catch (IOException e) {}
      if (player != null) game.getPlayers().remove(player);
      server.removeClientSession(this);
      server.sendObjectToSessions(game.getGameState());
   }
   
   /**
    * Creates the player based on the PlayerStartup object.
    */
   public void startupPlayer(PlayerStartup playerStartup) {
      player = game.addPlayer(playerStartup);
      sendObject(
            new ClientStartup(
                  game.getPlayers(),
                  player,
                  new NewGame(
                        new Maze2(
                              game.getMaze().getMap(),
                              game.getMaze().getLights()),
                              game.getGameState()
                  )));
      if (game.isFull()) {
         server.sendObjectToSessions(game.getGameState());
      } else {
         server.sendObjectToSessions(new ServerMessage(game.getPlayers().size() + "/" + game.getMaxPlayers()));
      }
   }

   public Player getPlayer() {
      return player;
   }
}
